package problems;


public class Euler112 extends AbstractEuler {

	private static final double TARGET_RATIO = 0.99;
	
	@Override
	public Number calculate() {
		double ratio = 0;
		for (int i = 1, bouncyNumbers = 0; ratio < TARGET_RATIO; i++) {
			if (isBouncy(i)) bouncyNumbers++;
			ratio = bouncyNumbers / (double)i;
			if (ratio == TARGET_RATIO) return i;
		}
		
		fail("no exact ratio of " + TARGET_RATIO + " found"); return null;
	}

	@Override
	protected Number getCorrectAnswer() {
		return 1587000;
	}
	
	private boolean isBouncy(int i) {
		if (i < 101) return false;
		//if the last two digits are equal, it is too soon to tell if we are increasing or decreasing; chop off digits until we get a bearing.
		while (i % 10 == (i / 10) % 10) i /= 10;
		//if the last digit is greater than the second-last, the number is bouncy if it starts decreasing later on, and vice versa.
		boolean increasing = (i % 10) > ((i /= 10) % 10);
		//lop off digits, compare them to the next one to see if we're still consistently increasing/decreasing, and if we're down to one digit, we're done.
		while (i > 9) {
			int leastSignificantDigit = i % 10;
			i /= 10;
			if (
				(increasing && (i % 10 > leastSignificantDigit)) ||
				(!increasing && (i % 10 < leastSignificantDigit))
			) return true; //aha! a contradiction!
		}
		//no contradictions found; the number is entirely increasing or decreasing.
		return false;
	}
	
	public void testBouncy() {
		assertFalse("66420", isBouncy(66420));
		assertFalse("666555444", isBouncy(666555444));
		assertTrue("101", isBouncy(101));
		assertTrue("121", isBouncy(121));
		assertFalse("122", isBouncy(122));
		assertFalse("123", isBouncy(123));
		assertFalse("100", isBouncy(100));
		assertFalse("199", isBouncy(199));
		assertTrue("1099", isBouncy(1099));
		assertTrue("1211", isBouncy(1099));
		assertTrue("123454321", isBouncy(123454321));
		assertFalse("123456789", isBouncy(123456789));
		assertTrue("483500", isBouncy(483500));
		assertFalse("135799", isBouncy(135799));
		assertFalse("134468", isBouncy(134468));
		assertTrue("155349", isBouncy(155349));
	}

}
